package com.tangfuzhong.aop2;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.Method;

/**
 * <p><em>Created on 2021/12/28 4:50 下午</em></p>
 * 自定义实现简单AOP
 * 自定义的方法拦截器
 * @author fuzhongtang
 * @since 1.0.1
 */
public class UserMethodInterceptor implements MethodInterceptor {


    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        String methodName = invocation.getMethod().getName();// 方法名
        Object returnVal = null;

        /*
         * 根据方法名的不同设置不同的拦截策类 似于配置文件中的<aop:pointcut
         * expression="execution( xxxmethodName)"/>，以此定义切入点。
         *
         * spring框架中可以根据方法对应的包、对应的参数、返回值、方法名等多个条件，并结合正则表达式来定义切入点
         * 为了简单化，此处我只用方法名的前缀来定义切入点。
         *
         */

        if (methodName.startsWith("add")) {

            returnVal = beforeEnhance(invocation);

        } else if (methodName.startsWith("delete")) {
            returnVal = afterThrowingEnhance(invocation);
        } else {
            returnVal = invocation.proceed();
        }

        return returnVal;
    }

    /*
     * 前置增强策略
     */
    private Object beforeEnhance(MethodInvocation mi) throws Throwable {
        /*
         * spring框架通过配置文件或注解来获得用户自定义的增强方法名及对其JavaBean的类名， 然后通过反射机制动态地调用用户的增强方法。
         * 为了简单化的测试，我这里将增强方法及对应的类给定死了、不能改动， 增强JavaBean就是ConsoloEnhancer，
         * 增强方法就是"public void before(MethodInvocation mi)"
         *
         */
        new ConsoloEnhancer().before(mi); // 调用用户定义的前置处理方式
        Object returnVal = mi.proceed(); // 执行目标方法
        return returnVal;
    }

    /*
     * 异常处理策略
     */
    private Object afterThrowingEnhance(MethodInvocation mi) throws Throwable {
        try {
            return mi.proceed();// 执行目标方法
        } catch (Throwable e) {
            new ConsoloEnhancer().afterThrowing(mi, e); // 调用用户定义的异常处理方式
            throw e;

        }

    }
}
